// crt0-app.S
// Applications downloaded in RAM using a debug monitor (eg. XMON, RedBoot)
// start here at _app_reset.  Such applications don't have any vectors:
// all exceptions are handled by the debug monitor.
// Thus, this file essentially plays the role of the reset vector
// to setup a few things before jumping to _start (in crt1*.S).

// Copyright (c) 2005-2013 Tensilica Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include <xtensa/cacheattrasm.h>
#include <xtensa/coreasm.h>


//  Assumptions on entry to _app_reset:
//	- debug monitor handles all exceptions, has setup all vectors
//	- interrupt related state is initialized
//	  (interrupts disabled or enabled for debug monitor's purposes)
//	- debug option related state is initialized (for debug monitor)
//	- any MMU related state is initialized (all handled by debug monitor)
//	- caches are initialized (cache attributes not necessarily correct)
//	- entire application is loaded (no unpacking needed here)

//  Assumptions on exit from _app_reset, ie. when jumping to _start:
//	- low (level-one) and medium priority interrupts are disabled
//	- C calling context not initialized:
//	  - PS not fully initialized (eg. PS.WOE not set per ABI)
//	  - SP not initialized
//	- the following are initialized:
//	  - LITBASE, WindowBase, WindowStart, LCOUNT, CPENABLE, FP's FCR and FSR,
//	    cache attributes

/**************************************************************************/

	.text
	.global	_app_reset
_app_reset:
	/* _app_reset may be required to be located at the beginning of the text
	   segment.  However, the constant pool for _app_reset must be placed
	   before the code.  Jump over the constant pool to solve this. */
	j	.LpastInitialConstants

	.literal_position	// tells the assembler/linker to place literals here

.LpastInitialConstants:
	// Keep a0 zero.  It is used to initialize a few things.
	// It is also the return address, where zero indicates
	// that the frame used by _start is the bottommost frame.
	//
	movi	a0, 0		// keep this register zero.

#if XCHAL_HAVE_LOOPS
	wsr.lcount	a0		// loop count = 0
#endif /* XCHAL_HAVE_LOOPS */

	// Interrupts might be enabled, make sure at least medium and low priority
	// interrupts are disabled until WindowBase, WindowStart, SP, and the stack
	// are all properly setup (which will happen outside this file, after the
	// _start label).  We leave loops enabled on new exception architecture.
#if XCHAL_HAVE_EXCEPTIONS
	movi	a2, XCHAL_EXCM_LEVEL
	wsr.ps	a2		// set PS.INTLEVEL=EXCM_LEVEL, PS.WOE=0, PS.EXCM=0
	rsync
#endif

	// DO THIS FIRST: initialize the window start and base
	// before, so that windows don't move under us.
#if XCHAL_HAVE_WINDOWED
	// We do this even if we are assembling for the
	// call0 abi, but it's not really needed.
	movi	a2, 1
	wsr.windowstart	a2		// window start = 1
	wsr.windowbase	a0		// window base = 0
	rsync

	// NOTE:  a0 may no longer be zero here, because
	// we wrote to WindowBase.  So clear it again.
	movi	a0, 0
#endif

	// Now, BEFORE we do any L32R (or MOVI with non-immediate
	// range which results in an L32R), ensure LITBASE is set
	// correctly.  This is necessary for RAM applications loaded
	// using a target-side debug monitor -- such applications
	// don't have a reset vector and start execution at _start.
	// (This part is unnecessary if running from a reset vector.)
	// The target-side debug monitor might have set LITBASE to
	// anything at all, so we cannot rely on its value here.
#if XCHAL_HAVE_ABSOLUTE_LITERALS
	wsr.litbase	a0			// force PC-relative L32R
	rsync
# if XSHAL_USE_ABSOLUTE_LITERALS
	.begin	no-absolute-literals		// use PC-rel L32R to load
	movi	a2, _lit4_start + 0x40001	// address of absolute literals
	.end	no-absolute-literals		// (see handlers/ResetVector.S
	wsr.litbase	a2			//  for explanation)
	rsync
# endif
#endif


	/*
	 *  Now "enable" the caches.
	 *
	 *  NOTE:  We don't *initialize* the caches here, because the loader
	 *  (eg. target debugger agent / debug monitor, boot code, etc)
	 *  is expected to have initialized them for us.
	 *
	 *  The _memmap_cacheattr_reset symbol's value (address) is defined
	 *  by the LSP's linker script, as generated by xt-genldscripts.
	 *
	 *  (NOTE:  for configs that don't have CACHEATTR or region protection,
	 *   ie. for full MMUs, there is no equivalent cache attribute layout,
	 *   and the following code has no effect.  We assume for now that the
	 *   application restricts itself to the static TLB entries, i.e. to
	 *   virtual addresses 0xD0000000 thru 0xFFFFFFFF.)
	 */
#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR \
		|| (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY)
	movi	a2, _memmap_cacheattr_reset	/* note: absolute symbol, not a ptr */
	cacheattr_set				/* set CACHEATTR from a2 (clobbers a3-a8) */
#endif



	// Coprocessor option initialization
#if XCHAL_HAVE_CP
	//movi	a2, XCHAL_CP_MASK	// enable existing CPs
	//  To allow creating new coprocessors using TC that are not known
	//  at GUI build time without having to explicitly enable them,
	//  all CPENABLE bits must be set, even though they may not always
	//  correspond to a coprocessor.
	movi	a2, 0xFF	// enable *all* bits, to allow dynamic TIE
	wsr.cpenable	a2
#endif

	// Floating point coprocessor option initialization
#if XCHAL_HAVE_FP
	rsync		/* wait for WSR to CPENABLE to complete before accessing FP coproc state */
	wur.fcr	a0     /* clear FCR (default rounding mode, round-nearest) */
	wur.fsr	a0     /* clear FSR */
#endif


	/*  NOTE:  Future releases may clear BSS here rather than in the CRT1.  */


	/*
	 *  Now jump to the application.  This is typically the
	 *  C run-time initialization ("CRT") which in turn calls main():
	 */
	movi	a4, _start
	jx	a4		// jump to _start

	.size	_app_reset, . - _app_reset

